Tables

 

 

 

 

 

 

Suppose, you want to maintain a large set of objects and you need to access them as fast as possible. Mapping mechanism in Java allows you do this associating a key to each object. Java introduces a concept called Map. A Map is a data structure that's designed for fast lookups.  In map, data is stored in key-object pairs with every key being unique.  That is, no two objects should have the same key. Each key maps to anobject and hence the name.  These pairs are called map entries. With this, the user’s view of storing objects looks like a table as shown in Figure 9.1.

 

Example:

 

Key

Object

k1

o1

k2

o2

k3

o2

k4

o5

k5

o9

k6

o6

Figure 9.1: Concept of map table in Java

 

In other words, for an object (o), there is a key (k); mathematically , where h denotes a function. Intuitively, this function h is called a hash function. Thus, map data structure models the function abstraction in mathematics. Figure 9.2 illustrates a map:

 

Figure 9.2:  Map as a mathematical abstraction of function

 

Some examples of maps

Maps are perfect to use for key-value association mapping such as dictionaries. The maps are used to perform lookups by keys or when someone wants to retrieve and update elements by keys. Some examples are:

 

·         Filenames and their contents stored in a secondary storage place.

·         All error codes and their descriptions for a system.

·         Zip codes and delivery destinations in a courier service.

·         A map of managers and employees. Each manager (key) is associated with a list of employees (value) he manages.

·         A map of classes and students. Each class (key) is associated with a list of students (value).

 

Following are some important characteristics about Map.

1.       A map is a mechanism for the fast retrieval of an object.

2.       In a map, an entry is characterized with a pair of elements: key and object.

3.       Given a key you can find an object. In other words, retrieving an object requires a key to be supplied.

4.       The keys must be unique, but the objects may be duplicated.

5.       A map cannot contain duplicate keys. 

6.       Mathematically, map implements an one-to-many and onto association.

 

Hash function for mapping

For the key-object association, a hash function is required. This hash function, in fact, generates a code called hash code. That is, with , h being the hash function, given an object o, h returns a unique value k.  In general, his system dependent and for the internal use of the system.

 

Example 9.1: Hash functions

 

A simple hash function is defined as follows.

 

h(k) = k mod 19

 

Here, mod is modulo remainder operation. Some examples are:

 

h(123) = 5

h(99) = 4

h(2014) = 0

 

Note that in this example, the hash function generates has codes within the rang [0, 1, …, 18] for any integer numbers. Thus, a key k is used to generate a hash code, which determines where in memory the <k, o> pair is stored. This is why a map is also sometime referred as a dictionary because of the way it works.

 

Note:

·         A key can be obtained for any kind of object that you want to use as reference to objects, lke integer, string, any used defined data type, such as Student, Book, etc.

·         Since the keys have to uniquely identify the objects, all keys in a map must be different.

·         In Java, there is a method called hashCode() defined in the class Object, which produces a hash code of type int for any object. The method as it is implemented in Java, usually it is the memory address where an object is stored. Thus the method always produces distinct hash code for distinct objects.

·         Further, you can overwrite the method hashCode() for your own defined class of objects. Here is an example, how you can do that.

 

Example 9.2: Generating hash code for a user defined object

 

    class Person {

String firstName;

String lastName;

int age;

 

Person (String f, String l, int a) {

      firstName = f;

lastname = l;

age = a;

            }

 

public int hashCode() {

      return (5*firstName.hashCode()

+ 7 * lastName.hashCode()

+ 11 *age.hashCode() );

            }

     

            public static void main(String args{}) {

                  P p = new Person(“Rajat”, “Ray”, 21);

                  int k = p.hashCode();

                  System.out.println(p + “has code “ + k);

            }

        }

                                               

Hierarchy of Map in Java Collection Framework

Java introduces the concept of Map, which is another member in the Java Collection Framework. In Java, a Map is an object that maps keys to values, or is a collection of key-value pairs. It models the function abstraction in mathematics.

 

In java.uti package, a number of interfaces and classes are defined and declared to support map objects in Java program. A part of the important interfaces and  classes is shown in Fig. 9.3.

 

 

Figure 9.3: Hierarchy of Map collection

 

The following are the interfaces declared in java.util package. See Table 9.1.

 

 

Interface

Description

Map

Mapsuniquekeystovalues. The interface is generic and it is defined as interface Map<K, V>, where K specifies the type of keys, and V specifies the type of values.

Map.Entry

Describesanelement(akey/valuepair)inamap.ThisisaninnerclassofMap.

NavigableMap

ExtendsSortedMaptohandletheretrievalofentriesbasedonclosest-matchsearches.

SortedMap

ExtendsMapsothatthekeysaremaintainedinascendingorder.

Table 9.1: Interfaces for Map in Java Collection Framework

 

Table 9.2 lists all the classes which are defined in java.util package.

 

Class

Description

AbstractMap

ImplementsmostoftheMapinterface.

EnumMap

ExtendsAbstractMapfor usewith enumkeys.

HashMap

ExtendsAbstractMaptouseahashtable.

TreeMap

ExtendsAbstractMaptouseatree.

LinkedHashMap

ExtendsHashMaptoallowinsertion-orderiterations.

IdentityHashMap

ExtendsAbstractMapandusesreferenceequalitywhencomparingdocuments.

WeakHashMap

ExtendsAbstractMaptouseahashtablewithweakkeys.

Table 9.2:  The classes for map in Java Collection Framework

 

In the following, we shall discuss the interfaces and classes for handling map objects.

 

The Map interface

The methods defined in the Map interface are listed in Table 9.3.

 

Method

Description

void clear()

Removes all key/value pairs from the invoking map.

defaultVcompute(Kk,BiFunction<?superK,?superV,

?extendsV>func)

Callsfunctoconstructanewvalue.Iffuncreturnsnon-null,thenewkey/valuepairisaddedtothemap,anypreexistingpairingisremoved,andthenewvalueisreturned.Iffuncreturnsnull,anypreexistingpairingisremoved,andnullisreturned.

defaultVcomputeIfAbsent(Kk,Function<?superK, ?extendsV>func)

Returnsthevalueassociatedwiththekeyk.Otherwise,thevalueisconstructedthroughacalltofuncandthepairingisenteredintothemapandtheconstructedvalueisreturned.Ifnovaluecanbeconstructed,nullisreturned.

Default V computeIfPresent(K k, BiFunction<?superK,?superV,

?extendsV>func)

Ifkisinthemap,anewvalueisconstructedthroughacalltofuncandthenewvaluereplacestheoldvalueinthemap.Inthiscase,thenewvalueisreturned.Ifthevaluereturnedbyfuncisnull,theexistingkeyandvalueareremovedfromthemapandnullisreturned.

booleancontainsKey(Objectk)

Returnstrueiftheinvokingmapcontainskasakey.Otherwise,returnsfalse.

booleancontainsValue(Objectv)

Returnstrueifthemapcontainsvasavalue.Otherwise,returnsfalse.

Set<Map.Entry<K,V>>entrySet()

ReturnsaSetthatcontainstheentriesinthemap.ThesetcontainsobjectsoftypeMap.Entry.Thus,thismethodprovidesaset-viewoftheinvokingmap.

booleanequals(Objectobj)

ReturnstrueifobjisaMapandcontainsthesameentries.Otherwise,returnsfalse.

defaultvoidforEach(BiConsumer<

?superK,

?superV>action)

Executesactiononeachelementintheinvokingmap.AConcurrentModificationExceptionwillbethrownifanelementisremovedduringtheprocess.

Vget(Objectk)

Returnsthevalueassociatedwiththekeyk.Returns

nullifthekeyisnotfound.

defaultVgetOrDefault(Objectk,VdefVal)

Returnsthevalueassociatedwithkifitisinthemap.Otherwise,defValisreturned.

inthashCode()

Returnsthehashcodefortheinvokingmap.

booleanisEmpty()

Returnstrueiftheinvokingmapisempty.Otherwise,returnsfalse.

Set<K>keySet()

ReturnsaSetthatcontainsthekeysintheinvokingmap.Thismethodprovidesaset-viewofthekeysintheinvokingmap.

defaultVmerge(Kk,Vv,BiFunction<?superV,?superV,

?extendsV>func)

Ifkisnotinthemap,thepairingk,visaddedtothemap.Inthiscase,visreturned.Otherwise,funcreturnsanewvaluebasedontheoldvalue,thekeyisupdatedtousethisvalue,andmerge()returnsthisvalue.Ifthevaluereturnedbyfuncisnull,theexistingkeyandvalueareremovedfromthemapandnullisreturned.

Vput(Kk,Vv)

Putsanentryintheinvokingmap,overwritinganypreviousvalueassociatedwiththekey.Thekeyandvaluearekandv,respectively.Returnsnullifthekeydidnotalreadyexist.Otherwise,thepreviousvaluelinkedtothekeyisreturned.

voidputAll(Map<?extendsK,

?extendsV>m)

Putsalltheentriesfrommintothismap.

defaultVputIfAbsent(Kk,Vv)

Insertsthekey/valuepairintotheinvokingmapifthispairingisnotalreadypresentoriftheexistingvalueisnull.Returnstheoldvalue.Thenullvalueisreturnedwhennopreviousmappingexists,orthevalueisnull.

Vremove(Objectk)

Removestheentrywhosekeyequalsk.

defaultbooleanremove(Objectk,Objectv)

Ifthekey/valuepairspecifiedbykandvisintheinvokingmap,itisremovedandtrueisreturned.Otherwise,falseisreturned.

defaultbooleanreplace(Kk,VoldV,VnewV)

Ifthekey/valuepairspecifiedbykandoldVisintheinvokingmap,thevalueisreplacedbynewVandtrueisreturned.Otherwisefalseisreturned.

defaultVreplace(Kk,Vv)

Ifthekeyspecifiedbykisintheinvokingmap,itsvalueissettovandthepreviousvalueisreturned.Otherwise,nullisreturned.

defaultvoidreplaceAll(BiFunction<

?superK,

?superV,

?extendsV>func)

Executesfunconeachelementoftheinvokingmap,replacingtheelementwiththeresultreturnedbyfunc.AConcurrentModificationExceptionwillbethrownifanelementisremovedduringtheprocess.

intsize()

Returnsthenumberofkey/valuepairsinthemap.

Collection<V>values()

Returnsacollectioncontainingthevaluesinthemap.Thismethodprovidesacollection-viewofthevaluesinthemap.

Table 9.3: Methods declared in Map interface.

 

Maps revolve around two basic operations: get( ) and put( ). To put a value into a map, use put( ), specifying the key and the value. To obtain a value, call get( ), passing the key as an argument. The value is returned.

Further, you can note that the Map interface is not a subtype of the Collection interface. Therefore, it behaves a bit different from the rest of the collection types, although part of the Collections Framework.  However, you can obtain a collection-view of a map. To do this, you can use the entrySet( ) method. It returns a Set that contains the elements in the map. To obtain a collection-view of the keys, use keySet(). To get a collection-view of the values, use the method values( ).

 

 

 

 

The StoredMap interface

The SortedMap interface extends Map. It ensures that the entries are maintained in ascending order based on the keys. SortedMap is generic like the interface Map.  The methods defined in the StoredMap interface are listed in Table 9.4.

 

Method

Description

Comparator<?superK>comparator()

Returnstheinvokingsortedmap’scomparator.Ifnaturalorderingisusedfortheinvokingmap,nullisreturned.

KfirstKey()

Returnsthefirstkeyintheinvokingmap.

SortedMap<K,V>headMap(Kend)

Returnsasortedmapforthosemapentrieswithkeysthatarelessthanend.

KlastKey()

Returnsthelastkeyintheinvokingmap.

SortedMap<K,V>subMap(Kstart,Kend)

Returnsamapcontainingthoseentrieswithkeysthataregreaterthanorequaltostartandlessthanend.

SortedMap<K,V>tailMap(Kstart)

Returnsamapcontainingthoseentrieswithkeysthataregreaterthanorequaltostart.

Table 4: The methods declared in StoredMap interface

 

The NavigableMap interface

The NavigableMap interface extends SortedMap and declares the behavior of a map that supports the retrieval of entries based on the closest match to a given key or keys. The NavigableMap is also a generic interface like the SortedMap and Map interfaces.  The methods defined in the NavigableMap interface are listed in Table 9.5.

 

 

Method

Description

Map.Entry<K,V>ceilingEntry(Kobj)

Searchesthemapforthesmallestkeyksuchthat

k>=obj.Ifsuchakeyisfound,itsentryisreturned.Otherwise,nullisreturned.

KceilingKey(Kobj)

Searchesthemapforthesmallestkeyksuchthatk >=obj. If sucha key isfound, it isreturned.Otherwise, nullis returned.

NavigableSet<K>descendingKeySet()

ReturnsaNavigableSetthatcontainsthekeysintheinvokingmapinreverseorder.Thus,itreturnsareverseset-viewofthekeys.Theresultingsetisbackedbythemap.

NavigableMap<K,V>descendingMap()

ReturnsaNavigableMapthatisthereverseoftheinvokingmap.Theresultingmapisbackedbytheinvokingmap.

Map.Entry<K,V>firstEntry()

Returnsthefirstentryinthemap.Thisistheentrywiththeleastkey.

Map.Entry<K,V>floorEntry(Kobj)

Searchesthemapforthelargestkeyksuchthatk<=obj.Ifsuchakeyisfound,itsentryisreturned.Otherwise,nullisreturned.

KfloorKey(Kobj)

Searchesthemapforthelargestkeyksuchthatk<=obj.Ifsuchakeyisfound,itisreturned.Otherwise,nullisreturned.

NavigableMap<K,V>

headMap(KupperBound,booleanincl)

ReturnsaNavigableMapthatincludesallentriesfromtheinvokingmapthathavekeysthatarelessthanupperBound.Ifinclistrue,thenanelementequaltoupperBoundisincluded.Theresultingmapisbackedbytheinvokingmap.

Map.Entry<K,V>higherEntry(K  obj)

Searchesthesetforthelargestkeyksuchthat

k>obj.Ifsuchakeyisfound,itsentryisreturned.Otherwise,nullisreturned.

KhigherKey(Kobj)

Searchesthesetforthelargestkeyksuchthatk>obj.Ifsuchakeyisfound,itisreturned.Otherwise,nullisreturned.

Map.Entry<K,V>lastEntry()

Returnsthelastentryinthemap.Thisistheentrywiththelargestkey.

Map.Entry<K,V>lowerEntry(Kobj)

Searchesthesetforthelargestkeyksuchthatk<obj.Ifsuchakeyisfound,itsentryisreturned.Otherwise,nullisreturned.

K lowerKey(Kobj)

Searchesthesetforthelargestkeyksuchthatk<obj.Ifsuchakeyisfound,itisreturned.Otherwise,nullisreturned.

NavigableSet<K>navigableKeySet()

ReturnsaNavigableSetthatcontainsthekeysintheinvokingmap.Theresultingsetisbackedbytheinvokingmap.

Map.Entry<K,V>pollFirstEntry()

Returnsthefirstentry,removingtheentryintheprocess.Becausethemapissorted,thisistheentrywiththeleastkeyvalue.nullisreturnedifthemapisempty.

Map.Entry<K,V>pollLastEntry()

Returnsthelastentry, removingtheentryintheprocess.Becausethemapissorted,thisistheentrywiththegreatestkeyvalue.nullisreturnedifthemapisempty.

NavigableMap<K,V>subMap(KlowerBound,

booleanlowIncl,KupperBoundbooleanhighIncl)

ReturnsaNavigableMapthatincludesallentriesfromtheinvokingmapthathavekeysthataregreaterthanlowerBoundandlessthanupperBound.IflowInclistrue,thenanelementequaltolowerBoundisincluded.IfhighInclistrue,thenanelementequaltohighInclisincluded.Theresultingmapisbackedbytheinvokingmap.

NavigableMap<K,V>

tailMap(KlowerBound,booleanincl)

ReturnsaNavigableMapthatincludesallentriesfromtheinvokingmapthathavekeysthataregreaterthanlowerBound.Ifinclistrue,thenanelementequaltolowerBoundisincluded.Theresultingmapisbackedbytheinvokingmap.

Table 9.5: The methods declared in NavigableMap interface

 

 

 

The Map.Entry interface

The Map.Entry interface enables you to work with a map entry. Recall that the entrySet( ) method declared by the Map interface returns a Set containing the map entries. Each of these set elements is a Map.Entry object. Map.Entry is generic and is declared like this: interface Map.Entry<K, V> Here, K specifies the type of keys, and V specifies the type of values. Table 9.6 summarizes the non-static methods declared by Map.Entry.

 

 

Method

Description

Boolean equals(Object obj)

Returns true if obj is a Map.Entry whose key and value are equal to that of the invoking object.

K getKey()

Returns the key for this map entry.

V getValue()

Returns the value for this map entry.

Int hashCode()

Returns the hash code for this map entry.

V setValue(V v)

Sets the value for this map entry to v. A ClassCastException

Is thrown if v is not the correct type for the map. An IllegalArgumentException is thrown if there is a problem with v. A NullPointerException is thrown if v is null and the map does not permit null keys. An UnsupportedOperationException is thrown if the map cannot be changed.

Table 9.6: The methods declared in Map.Entry interface

 

The Map classes

There are several classes (also see Fig. 9.3 and Table 9.2) to implement the map interfaces. All classes extends the AbstractMap class, which in turns implements the Map interface. This implies that all the methods in the Map interface are mostly defined in them in addition to some of their own methods. In the following, a brief description of each class followed by the constructors and methods are briefly discussed. Following this, the utility of each class with reference to the following activities are also discussed.

 

·         Creating a map container

·         Storing objects into a map container

·         Retrieving objects from a map container

·         Removing objects from a map container

·         Collection view of a map container

·         Bulk operations on a Map container

Following are the basic operations of a Map along with the methods defined in Map framework:

 

·         Association (put)

·         Lookup (get)

·         Checking (contains Key and contains Value)

·         Modification (remove and replace)

·         Cardinality (size and isEmpty).

 

 

 

The EnumMap class

This class defines keys of an enum type. It is a generic class that has this declaration:

 

class EnumMap<K extends Enum<K>, V>

 

Here, K specifies the type of key, and V specifies the type of value. Notice that K must extend Enum<K>, which enforces the requirement that the keys must be of an enum type.

 

EnumMap defines the following constructors which is shown in Table 9.7:

 

Constructor

Description

EnumMap(Class<K>kType)

This constructor creates an empty EnumMap of type kType.

EnumMap(Map<K, ? extends V> m)

 

This constructor creates an EnumMap map that contains the same entries as m.

EnumMap(EnumMap<K, ? extends V>em)

To create an EnumMap initialized with the values in em.

Table 9.7. The constructors in EnumMap class

 

There are no class of its own defined in EnumMap class.

 

The HashMap class

This class is used to create a hash table to store the map. The execution of get( ) and put() method can be done in a constant time irrespective of the size of the table because of the use of hash value of key.  HashMap is a generic class and it has the following declaration:

class HashMap<K, V>

 

Here, K specifies the type of keys, and V specifies the type of values.

 

HashMap defines the following constructors which is shown in Table 9.8:

 

Constructor

Description

HashMap( )

This constructor creates a default hash map.

HashMap(Map<? extends K, ? extends V> m)

The form is to initialize the hash map  using the elements of m.

HashMap(int capacity)

The third form initializes the capacity of the hash map to capacity.

HashMap(int capacity, float fillRatio)

The fourth form initializes both the capacity and fill ratio of the hash map by using its arguments. The meaning of capacity and fill ratio is the same as for HashSet, described earlier. The default capacity is 16. The default fill ratio is 0.75.

Table 9.8. The constructors in HashMap class

 

Like EnumMap, there is no class of its own defined in HashMap class.

 

Example 9.3a:  Creating a Map container using HashMap class and storing objects into it

The following example creates a map container using the put() method.

 

import java.util.*;

 

class HashMapCreateDemo {

public static void main(String args[]) {

// Create a hash map object as a container.

HashMap<Double, String>hMap = new HashMap<Double, String>();

 

// Put elements to the map container

hMap.put(200.0, "OK");

hMap.put(303.0, "See Other");

hMap.put(404.0, "Not Found");

hMap.put(500.0, "Internal Server Error");

 

System.out.println(hMap);  // Printing the container

      }

}

 

Note:

·         Alternatively, you could use interface type (Map) to declare the hashMap object. For example,

 

Map<String, Double>hMap = new HashMap<String, Double>();

 

·         Always use generics and diamond operator to declare a new map.

·         As you can see in the output, a HashMap does not impose any order on its key-value elements.

·         If you put an object with the same key value, it will overwrite the previous one.

 

Example 9.3b:   Storing objects into a Map container using HashMap class with duplicate values

The following example creates a map container using the put() method and with duplicate entries.

 

import java.util.*;

 

class HashMapDuplicateDemo {

public static void main(String args[]) {

// Create a hash map object as a container.

HashMap<Integer, String>hMap = new HashMap<Integer, String>();

 

// Put elements to the map container with duplicates

hMap.put(200, "OK");

hMap.put(303, "See Other");

hMap.put(404, "Not Found");

hMap.put(500, "Internal Server Error");

hMap.put(303, "Inavlid entry");

hMap.put(101, "See Other");

 

System.out.println(hMap);  // Printing the container

      }

}

 

Example 9.3c:   Creating and storing a Map container using HashMap class with copy

The following example creates a map container that copies elements from an existing map.

 

import java.util.*;

 

class HashMapCopyDemo {

public static void main(String args[]) {

// Create a hash map object as a container.

Map<String, Double> hMap1 = new HashMap<>();

 

// Put elements to the map container 

hMap1.put("John Doe", new Double(3434.34));

hMap1.put("Tom Smith", new Double(123.22));

hMap1.put("Jane Baker", new Double(1378.00));

hMap1.put("Tod Hall", new Double(99.22));

hMap1.put("Ralph Smith", new Double(-19.08));

System.out.println(hMap1);  // Printing the container

 

// Create a copy of a hMap1 to hMap2

Map<String,Double> hMap2 = new HashMap<>(hMap1);

 

// Add data into hMap2

hMap1.put("RobinKeith", new Double(423.22));

hMap1.put("PeterHwang", new Double(178.00));

System.out.println(hMap2);  // Printing the container

     }

}

 

Example 9.4:  Retrieving objects from a Map container

The following example illustrates how an object stored in a map framework can be accessed. For this, you should use the get().

 

import java.util.*;

 

class HashMapAcsessDemo {

public static void main(String args[]) {

// Create a hash map object as a container.

Map<String, Double>hMap = new HashMap<>();

 

// Put elements to the map container 

hMap.put("John Doe", new Double(3434.34));

hMap.put("Tom Smith", new Double(123.22));

hMap.put("Jane Baker", new Double(1378.00));

hMap.put("Tod Hall", new Double(99.22));

hMap.put("Ralph Smith", new Double(-19.08));

 

// Deposit 1000 into John Doe's account.

double balance = hMap.get("John Doe");

hMap.put("John Doe", balance + 1000);    

     

System.out.println("John Doe's current balance: " + hMap.get("John Doe"));

}

}

 

Example 9.5:   Removing objects from a Map container

There are two methods, namely remove() and replace()  that you can use for remove an entry in a map framework. The following example illustrates how an object stored in a map framework can be removed. 

 

import java.util.*;

 

class HashMapRemoveDemo {

public static void main(String args[]) {

// Create a hash map object as a container.

Map<String, Double>hMap = new HashMap<>();

 

// Put elements to the map container 

hMap.put("John Doe", new Double(3434.34));

hMap.put("Tom Smith", new Double(123.22));

hMap.put("Jane Baker", new Double(1378.00));

hMap.put("Tod Hall", new Double(99.22));

hMap.put("Ralph Smith", new Double(-19.08));

 

double val = hMap.remove("Jane Baker");

 

if (val != null) {

System.out.println("Removed value: " + val);

}    

System.out.println(hMap);

 

hMap.remove("Tod Hall", 99.22);

System.out.println(hMap);

 

hMap.replace("Ralph Smith", 545.67);

System.out.println(hMap);

}

}

 

Note:

·         The remove(Object key) method removes the mapping for a key from the map if it is present (we care about only the key, and the value does not matter). This method returns the value to which the map previously associated the key, or null if the map doesn’t contain mapping for the key.

·         Similarly, the remove(Object key, Object value) method removes the mapping of a specified key and specified value, and returns true if the value was removed. This method is useful in case we really care about the key and value to be removed.

·         The replace(K key, V value)method replaces the entry for the specified key only if it is currently mapping to some value. This method returns the previous value associated with the specified key. Here’s an example:

 

Example 9.6a:   Viewing a Map container : Status of a map

There are two methods, namely size() and isEmpty()  that can be used to check the status of a map container.  The following example illustrates how an object stored in a map framework can be viewed. 

 

import java.util.*;

 

class HashMapViewDemo {

public static void main(String args[]) {

// Create a hash map object as a container.

HashMap<String, Double>hMap = new HashMap<String, Double>();

 

// Put elements to the map container

hMap.put(200, "OK");

hMap.put(303, "See Other");

hMap.put(404, "Not Found");

hMap.put(500, "Internal Server Error");

 

 

// Checking the container

if (hMap.isEmpty()) {

System.out.println("Error: The container is empty");

} else {

System.out.println(hMap);  // Printing the container

}

 

// Printing the size of the container

System.out.println(“Size : “ + hMap.size());

      }

}

 

Example 9.6b:   Viewing a Map container : Map iteration

As a Map is not a true collection, there is no direct method for iterating over a map. Instead, we can iterate over a map using its collection views. Any Map’s implementation has to provide the following four Collection view methods:

 

keySet(): returns a Set view of the keys contained in the map. Hence we can iterate over the keys of the map.

 

values(): returns a collection of values contained in the map. Thus we can iterate over values of the map

 

entrySet(): returns a Set view of the mappings contained in this map. Therefore, we can iterate over mappings in the map using the set view.

 

forEach()and Lambda expression: Additionally, you can use the Lambda expressions and the forEach() statement to view the map container. 

 

The following program illustrates the above here ways f iterating over a map container.

 

import java.util.*;

 

class HashMapIterationDemo {

public static void main(String args[]) {

// Create a hash map object as a container.

Map<String, String>mapCountryCodes = newHashMap<>();

 

mapCountryCodes.put("1", "USA");

mapCountryCodes.put("44", "United Kingdom");

mapCountryCodes.put("33", "France");

mapCountryCodes.put("81", "Japan");

mapCountryCodes.put("91", "India");

 

              // Collection view using keySet()

Set<String>setCodes = mapCountryCodes.keySet();

Iterator<String> iterator = setCodes.iterator();

              while(iterator.hasNext()) {

                  String code = iterator.next();

                  String country = mapCountryCodes.get(code);

                  System.out.println(code + " => "+ country);

      }

 

            // Collection view using values()

            Collection<String> countries = mapCountryCodes.values();

for(String country : countries) {

                  System.out.println(country);

}

 

// Collection view using entrySet()

Set<Map.Entry<String, String>> entries =

mapCountryCodes.entrySet();

              for(Map.Entry<String, String>entry : entries) {

                  String code = entry.getKey();

                  String country = entry.getValue();

                     System.out.println(code + " => "+ country);

}

 

// Collection view using Lambda expression

mapCountryCodes.forEach((code, country) ->

            System.out.println(code + " => "+ country));

 

}

}

 

 

Example 9.7:  Performing Bulk Operations with Maps

There are the following two bulk operations with maps.

clear() : The clear() method removes all mappings from the map. The map will be empty after this method returns.

putAll() : The putAll(Map<K, V> m) method copies all of the mappings from the specified map to this map.

 

Following program illustrates the said two operations with a map collection.

 

import java.util.*;

 

class HashMapBulkOperationDemo {

public static void main(String args[]) {

// Create two map object containers.

Map<Integer, String>countryCodesEU = new HashMap<>();

            countryCodesEU.put(44, "United Kingdom");

countryCodesEU.put(33, "France");

countryCodesEU.put(49, "Germany");

 

Map<Integer, String>countryCodesWorld = new HashMap<>();

            countryCodesWorld.put(1, "United States");

countryCodesWorld.put(86, "China");

countryCodesWorld.put(82, "South Korea");

 

            System.out.println("Before: " + countryCodesWorld);

     

            // Merger two containers using putAll()

            countryCodesWorld.putAll(countryCodesEU);

 

System.out.println("After: " + countryCodesWorld);

 

// Clear one map container

countryCodesEU.clear();

System.out.println("Is map empty? "+ countryCodesEU.isEmpty());

 

}

}

 

 

The TreeMap class

The TreeMap creates maps stored in a tree structure. A TreeMap provides an efficient means of storingkey/value pairs in sorted order and allows rapid retrieval. You should note that, unlike a hash map, a tree map guarantees that its elements will be sorted in ascending key order.

 

The TreeMap class extends AbstractMap and implements the NavigableMap interface. TreeMap is a generic class that has this declaration:

 

class TreeMap<K, V>

 

Here, K specifies the type of keys, and V specifies the type of values.

 

TreeMap defines the following constructors which is shown in Table 9.9:

 

Constructor

Description

TreeMap( )

The first form constructs an empty tree map that will be sorted by using the natural order of its keys.

TreeMap(Comparator<? super K> comp)

The second form constructs an empty tree-based map that will be sorted by using the Comparator comp. (Comparators are discussed later in this chapter.)

TreeMap(Map<? extends K, ? extends V> m)

The third form initializes a tree map with the entries from m, which will be sorted by using the natural order of the keys..

TreeMap(SortedMap<K, ? extends V>sm)

The fourth form initializes a tree map with the entries from sm, which will be sorted in the same order as sm.

Table 9.9. The constructors in TreeMap class

 

TreeMap has no map methods beyond those specified by the NavigableMap interface and the AbstractMap class.

 

Example 9.8:  Managing a Map container as a TreeMap class object

All the operations you have learned for the HashMap class is equally applicable with TreeMap class. The following example illustrates few such operation in a single program.

 

import java.util.*;

 

class TreeMapDemo {

public static void main(String args[]) {

// Create a tree map.

TreeMap<String, Double> tm = new TreeMap<String, Double>();

// Put elements to the map.

tm.put("John Doe", new Double(3434.34));

tm.put("Tom Smith", new Double(123.22));

tm.put("Jane Baker", new Double(1378.00));

tm.put("Tod Hall", new Double(99.22));

tm.put("Ralph Smith", new Double(-19.08));

 

// Get a set of the entries.

Set<Map.Entry<String, Double>> set = tm.entrySet();

 

// Display the elements.

for(Map.Entry<String, Double> me : set) {

System.out.print(me.getKey() + ": ");

System.out.println(me.getValue());

}

System.out.println();

 

// Deposit 1000 into John Doe's account.

double balance = tm.get("John Doe");

tm.put("John Doe", balance + 1000);

System.out.println("John Doe's new balance: " +

tm.get("John Doe"));

}

}

 

The LinkedHashMap class

It maintains a linked list of the entries in the map, in the order in which they were inserted. This allows insertion-order iteration over the map. That is, when iterating through a collection-view of a LinkedHashMap, the elements will be returned in the order in which they were inserted. You can also create a LinkedHashMap that returns its elements in the order in which they were last accessed. LinkedHashMap is a generic class that has this declaration:

 

class LinkedHashMap<K, V>

 

Here, K specifies the type of keys, and V specifies the type of values.

 

LinkedHashMap extends HashMap. LinkedHashMap defines the following constructors which is shown in Table 9.10:

 

Constructor

Description

LinkedHashMap( )

It is a default constructor.

LinkedHashMap(Map<? extends K, ? extends V> m)

This constructor initializes the LinkedHashMap with the elements from m.

LinkedHashMap(int capacity)

The third form initializes the capacity.

LinkedHashMap(int capacity, float fillRatio)

initializes both capacity and fill ratio. The default capacity is 16. The default ratio is 0.75.

LinkedHashMap(int capacity, float fillRatio, boolean Order)

Itallows you to specify whether the elements will be stored in the linked list by insertion order, or by order of last access. If Order is true, then access order is used. If Order is false, then insertion order is used.

Table 9.10:  The constructors in LinkedHashMap class

 

LinkedHashMap adds only one method to those defined by HashMap. This method is removeEldestEntry(), and it is shown here:

 

protected booleanremoveEldestEntry(Map.Entry<K, V> e)

 

This method is used keep a track of whether the map removes any eldest entry from the map. So each time a new element is added to the LinkedHashMap, the eldest entry is removed from the map. This method is generally invoked after the addition of the elements into the map by the use of put() and putall() method. This method is called by put( ) and putAll( ). The oldest entry is passed in e. By default, this method returns false and does nothing. However, if you override this method, then you can have the LinkedHashMap remove the oldest entry in the map. To do this, have your override return true. To keep the oldest entry, return false.

 

Example 9.9:  Managing a Map container as a LinkedHashMap class object

The following program illustrates the creation of a Map object using LinkedHashMap class.

 

import java.util.*;

 

class LinkedHashMapDemo {

// Refers to the max size of the map following which the removal takes place

// of the eldest entry

private static final int MAX = 6;

 

public static void main(String args[]) {

// Creating the linked hashmap and implementing removeEldestEntry()

// to MAX size

LinkedHashMap<Integer, String>lhm = 

new LinkedHashMap<Integer, String>() {

                  protected booleanremoveEldestEntry(Map.Entry<Integer, String>

 eldest) {

                  return size() > MAX;

}

};

// Adding elements using put()

lhm.put(0, "Welcome");

lhm.put(1, "To");

lhm.put(2, "The");

lhm.put(3, "World");

lhm.put(4, "Of");

lhm.put(5, "Java");

 

System.out.println("" + lhm);

 

// Adding more elements

lhm.put(6, "Joy with Java");

 

// Displying the map after adding one more element

System.out.println("" + lhm);

 

// Adding more elements

lhm.put(7, "Hello");

 

// Displying the map after adding one more element

System.out.println("" + lhm);

}

}

 

Note:

·         This method allows the map to modify itself as directed by its return value. Although the method is permitted to modify the map directly, if it does so, it must return false which will be indicative of the fact that the map should not attempt any further modification leading to ambiguity. The effects of returning true after modifying the map from within this method are unspecified.

·         This is very useful when the map represents a cache where it allows the map to reduce memory consumption by deleting stale entries one after another.

 

Example 9.10:   Map container with user defined data type

All the examples can be extended to be applied to any class either built-in or user defined. The following example illustrates how a map container will be with objects of Book class.

 

import java.util.*;

 

class Book {   

int id;   

String name,author,publisher;   

int quantity;   

 

public Book(int id, String n, String a, String p, int q){   

            this.id = id;   

            name = n;   

            author = a;   

            publisher = p;   

            quantity = q;   

}   

}

 

public class MapBookDataExample {   

public static void main(String[] args) {   

            //Creating map of Books   

             Map<Integer,Book> map=new LinkedHashMap<Integer,Book>();   

 

//Creating Books   

            Book b1=new Book(101,"Python","Ponting","Oxford",8);   

            Book b2=new Book(102,"Java","Spielberg","McGraw Hill",4);   

            Book b3=new Book(103,"C++","Galvin","Wiley",6);   

 

//Adding Books to map  

            map.put(2,b2); 

            map.put(1,b1); 

            map.put(3,b3); 

 

            //Traversing map 

            for(Map.Entry<Integer, Book>entry:map.entrySet()){   

            int key=entry.getKey(); 

            Book b=entry.getValue(); 

            System.out.println(key+" Details:"); 

            System.out.println(b.id+" "+b.name+" "+b.author+"

"+b.publisher+" "+b.quantity);  

            }   

}   

}   

 

 

 

The IdentityHashMap class

The API documentation explicitly states that IdentityHashMap is not for general use and hence its discussion is ignored.

 

The IdentityHashMap class

WeakHashMap implements a map that uses “weak keys,” which allows an element in a map to be garbage-collected when its key is otherwise unused. This class is also not used for general use and is not discussed.

 

Note:

·         AbstractMapis a superclass for all concrete map implementations.

·         There are three interfaces for implementing Map in java: Map, SortedMap and NavigableMap, and four classes: EnumMap, HashMap, TreeMap and LinkedHashMap.

·         Map don’t implement the Iterable interface. This means that you cannot cycle through a map using a for-each style for loop. Furthermore, you can’t obtain an iterator to a map.

·         You can obtain a collection-view of a map, which does allow the use of either the for loop or an iterator.

 

Example 9.11:  A Map container using EnumMap class

The following Java program illustrates working of EnumMap and its functions.

 

import java.util.EnumMap;

 

public class Example {

    public enum SIZE    {S, M, L, X };    

 

    public static void main(String args[])     {    

        // Creating EnumMap in java with key   as enum type STATE

        EnumMap<SIZE, String>enuMap = new EnumMap<SIZE, String>(SIZE.class);

 

        //Putting values inside EnumMap in Java

        // Inserting Enum keys different from  their natural order

        enuMap.put(SIZE.S, "Children");

        enuMap.put(SIZE.M, "Young");

        enuMap.put(SIZE.L, "Aged");

        enuMap.put(SIZE.X, "Old");

         

        // Printing size of EnumMap in java

        System.out.println("Size of EnumMap in java: "+  enuMap.size());

      

        // Printing Java EnumMap 

        System.out.println("EnumMap: "+ enuMap);

      

        // Retrieving value from EnumMap in java

        System.out.println("Key : "+ SIZE.S +" Value: " +

enuMap.get(SIZE.S));

    }

}

 

 

Note:

·         EnumMap class is a member of the Java Collections Framework & is not synchronized.

·         EnumMap is ordered collection and they are maintained in the natural order of their keys( natural order of keys means the order on which enum constant are declared inside enum type )

·         It’s a high performance map implementation, much faster than HashMap.

·         All keys of each EnumMap instance must be keys of a single enum type.

·         EnumMap doesn’t allow null key and throw NullPointerException, at same time null values are permitted.

 

Concurrent Map

Unlike the legacy Hashtable which is synchronized, the HashMap, TreeMap and LinkedHashMap are not synchronized. If thread-safe is priority, consider using ConcurrentHashMap in place of HashMap. Or we can use the Collections.synchronizedMap() utility method that returns a synchronized (thread-safe) map backed by the specified map.

 

 

 

Example 9.12: Thread safe execution with HashMap collection

 

import java.util.*;

 

class HashMapSynchronizationDemo {

public static void main(String args[]) {

// Create two map object containers.

Map<Integer, String> map =

Collections.synchronizedMap(new HashMap<>());

 

// Creatin a map

            map.put(400, "Bad Request");

map.put(304, "Not Modified");

map.put(200, "OK");

map.put(301, "Moved Permanently");

map.put(500, "Internal Server Error");

 

 

Set<Integer>keySet = map.keySet();

 

synchronized(map) {

                  Iterator<Integer> iterator = keySet.iterator();

                        while(iterator.hasNext()) {

                              Integer key = iterator.next();

                              String value = map.get(key);

                        }

}

}

}

 

 

Note:

·         You should manually synchronize the map when iterating over any of its collection views.

·         If you use your own type for the key and value (e.g. Student or Employee), the key class and value class must implement the equals() and hashCode() methods properly so that the map can look up them correctly.